<?php
defined('IN_MAIN') or exit('Invalid Access!');

function calc_pairing_matching($in_year, $in_month, $in_day){
/*
This function calculate the pairing and matching bonus for the input in_date. This function will get all the purchases that is the first
purchase for a particular user (upgrade of member rank also considered as first sale, second and onwards purchase for a user will be calculated 
for another commission) for the input in_date and calculate the pairing in such a way that A will pair with B, then leftover from this pairing 
will pair with C, and leftover will pair with D, and so on, until all 5 legs have been processed. The maximum number of pair for a 
particular 2-leg pairing is 10 pair per day (for eg, if leg 1 pair with leg 2, max can pair 10 pairs, then leftover will pair with leg 3 also 
at maximum 10 pairs per day). Pairing occurs for each and every combination of member activation package, and only same level package can pair
with each other, for eg, 400 will only pair with 400, 1200 pair with 1200, and no 400 can pair with 1200 or other amount. Pairing will first
start at the top volume (6000, then 5600 - upgrade from 400 to 6000, then 4800 - upgrade from 1200 to 6000, and so on). When pairing with a
particular volume, whenever a 2-leg pair reaches a max 10 pairs, then only the biggest leftover leg will be carried forward (or pair with next
leg). This process is repeated for other volumes, and will use the total paired units to count as total pair per 2-leg. After pairing, the 
matching will calculate right away to the downline of the commission receiver.

On successful commission calculation, it will return boolean true, else it will return the error messages
*/

	//globalize access to pairing_percent_per_pair, max_pair_per_day, pairing_volume_type, rank_index_a_bv, matching_bonus
	
	global $vars;
	$db=$vars["db"];
	$pairing_percent_per_pair = $vars['pairing_percent_per_pair'];
	$max_pair_per_day = $vars['max_pair_per_day'];
	$pairing_volume_type = $vars['pairing_volume_type'];
	$rank_index_a_bv = $vars['rank_index_a_bv'];
	$matching_bonus = $vars['matching_bonus'];
	
	$start_time=mktime(0, 0, 0, $in_month, $in_day, $in_year);
	$calc_date['start']=date('Y-m-d H:i:s', mktime(0, 0, 0, $in_month, $in_day, $in_year));
	$calc_date['end']=date('Y-m-d H:i:s', mktime(23, 59, 59, $in_month, $in_day, $in_year));
	$calc_date2['start']=date('Y-m-d H:i:s', mktime(0, 0, 0, $in_month, 1, $in_year));
	$calc_date2['end']=date('Y-m-d H:i:s', mktime(23, 59, 59, $in_month+1, 0, $in_year));
	
	//matching_max_level = get the maximum of matching level
	//min_maintain = get the minimum maintenance
	$matching_max_level = count($matching_bonus);
	$min_maintain = $vars['min_maintain'];
	
	//xxx members = get all the members xxx - we don't we need to filter by maintain 200 as filter is done at reporting - that have personal maintain / purchases of more than min_maintain (200)
	//xxx members = get all the members that have maintain 200BV purchases in the month
	//members = get all the members that is activated
	$t=@mysql_num_rows($r=mysql_query("select id, rank_a from $db->users where activated='y'"));
	
	//foreach members
	for($i=0;$i<$t;$i++){
		$member = mysql_fetch_assoc($r);
		//uid = this member[id]
		$uid = $member['id'];
		//member_legs = get_member_matrix_leg(this member ID, pairing_volume_type, calc_date[start], calc_date[end]) //get this member all legs
		$member_legs = get_member_matrix_leg($uid, $pairing_volume_type, $calc_date['start'], $calc_date['end']);
		/*
			member_legs will then looks like this:
			member_legs[index][id]
			member_legs[index][position]
			member_legs[index][volume] - volume should include this day volume (1st sale of a member only) plus any carry forward from previous day if applicable
			member_legs[index][avolume] - avolume should include only this day volume (1st sale of a member only), without any carry forward
			member_legs[index][volume_type][unit]
				[volume_type] is the type of purchase (in BV), can be 400, 1200, 2800, 6000, 800, 2400, 5600, 1600, 4800, or 3200, 
				[unit] means how many of this type of purchase has occur within this leg for this day (1st sale of a member only) plus any carry forward from previous day if applicable
			member_legs[index][volume_type][left_unit] - same with unit
			member_legs[index][volume_type][aunit] - aunit should include only this day unit (1st sale of a member only), without any carry forward
			
			position is the matrix position, sort by largest volume (include carry forward) leg 1st (accumulated total of all volume as biggest)
		*/
		$pi = 0;
		unset ($total_paired_unit);
		unset ($max_pair_reached);
		for($j=0,$t2=count($pairing_volume_type);$j<$t2;$j++){
			$volume_type = $pairing_volume_type[$j];
			$prev_position = 0;
			$cur_position = 1;
			do{
				//continue_pair = false
				$continue_pair = false;
				//if isset member_legs[prev_position] and isset member_legs[cur_position]
				if (isset($member_legs[$prev_position]) && isset($member_legs[($cur_position)])){
					if($rank_index_a_bv[$member['rank_a']] >= $volume_type){
						//if member_legs[prev_position][volume_type][left_unit] >= 1 and member_legs[cur_position][volume_type][unit] >= 1
						if ($member_legs[$prev_position]['volume_type'][$volume_type]['left_unit'] >= 1 && $member_legs[$cur_position]['volume_type'][$volume_type]['unit'] >= 1){
							//if not max_pair_reached[cur_position]
							if (!$max_pair_reached[$cur_position]){
								//paired_unit = the least of member_legs[prev_position][volume_type][left_unit] and member_legs[cur_position][volume_type][unit]
								$paired_unit = ($a = $member_legs[$prev_position]['volume_type'][$volume_type]['left_unit']) > ($b = $member_legs[$cur_position]['volume_type'][$volume_type]['unit'])? $b : $a;
								if ($total_paired_unit[$cur_position] + $paired_unit > $max_pair_per_day){
									$paired_unit = $max_pair_per_day - $total_paired_unit[$cur_position];
								}
								if ($total_paired_unit[$cur_position] + $paired_unit >= $max_pair_per_day){
									$max_pair_reached[$cur_position] = true;
								}
								$total_paired_unit[$cur_position] += $paired_unit;
								$paired_amount = $paired_unit * $volume_type * $pairing_percent_per_pair / 100;
								$paired_comm[$uid][$pi]['paired_unit'] = $paired_unit;
								$paired_comm[$uid][$pi]['paired_amount'] = $paired_amount;
								$paired_comm[$uid][$pi]['volume_type'] = $volume_type;
								$paired_comm[$uid][$pi]['leg1'] = $member_legs[$prev_position]['position'];
								$paired_comm[$uid][$pi]['leg1_id'] = $member_legs[$prev_position]['id'];
								$paired_comm[$uid][$pi]['leg1_amount'] = $member_legs[$prev_position]['volume_type'][$volume_type]['left_unit'] * $volume_type;
								$paired_comm[$uid][$pi]['leg2'] = $member_legs[$cur_position]['position'];
								$paired_comm[$uid][$pi]['leg2_id'] = $member_legs[$cur_position]['id'];
								$paired_comm[$uid][$pi]['leg2_amount'] = $member_legs[$cur_position]['volume_type'][$volume_type]['left_unit'] * $volume_type;
								$pi++;
								$member_legs[$prev_position]['volume_type'][$volume_type]['left_unit'] -= $paired_unit;
								$member_legs[$cur_position]['volume_type'][$volume_type]['left_unit'] -= $paired_unit;
							}
						}
					}
					if ($max_pair_reached[$cur_position]){
						if ($member_legs[$prev_position]['volume_type'][$volume_type]['left_unit'] < $member_legs[$cur_position]['volume_type'][$volume_type]['left_unit']){
							$member_legs[$prev_position]['volume_type'][$volume_type]['left_unit'] = 0;//flush smaller leg
						}else{
							$member_legs[$cur_position]['volume_type'][$volume_type]['left_unit'] = 0;
						}
						//we do not need check for previous leg since if max pairing haven't reach for previous leg means the units
						//have been fully paired and no left
					}
					if ($member_legs[$prev_position]['volume_type'][$volume_type]['left_unit'] < $member_legs[$cur_position]['volume_type'][$volume_type]['left_unit']){
						$prev_position = $cur_position;
					}
					//cur_position += 1
					$cur_position += 1;
					//continue_pair = true
					$continue_pair = true;
				}
			}while ($continue_pair);
		}
		
		//carry forward for all legs with left_volume > 0
		for($j=0,$t2=count($member_legs);$j<$t2;$j++){
			for($k=0,$t3=count($pairing_volume_type);$k<$t3;$k++){
				if ($member_legs[$j]['volume_type'][$pairing_volume_type[$k]]['left_unit'] > 0){
					//insert into member_cf with uid = member_legs[index][id], leg = member_legs[index][position], volume_type= volume_type, amount = member_legs[index][volume_type][left_unit], year = year, month = month, day = day
					$sql="insert into $db->member_cf (uid, leg, volume_type, amount, cdate) values ('{$member_legs[$j]['id']}', '{$member_legs[$j]['position']}', '{$pairing_volume_type[$k]}', '{$member_legs[$j]['volume_type'][$pairing_volume_type[$k]]['left_unit']}', '".date('Y-m-d', $start_time)."')";
					$insert_comm_detail="UID: $uid Carryforward Amount: {$pairing_volume_type[$k]} x {$member_legs[$j]['volume_type'][$pairing_volume_type[$k]]['left_unit']} Leg: {$member_legs[$j]['position']} (DID: {$member_legs[$j]['id']})<br />\n";
					//if insert fail
						//record error in the variable insert_cf_error
					if(!mysql_query($sql)){
						$insert_cf_error.=$insert_comm_detail."SQL: $sql<br />\n";
					}
				}
			}
		}
		
		//matching
		//if count(paired_comm[uid])
		if (count($paired_comm[$uid])){
			//downline_id = uid
			$downline_id = $uid;
			$level = 1;
			do{
				if (!isset($member_info[$downline_id])){
					$member_info[$downline_id] = get_user_short_detail_by_id($downline_id);
				}
				$upline_id = $member_info[$downline_id]['ref'];
				if ($upline_id){
					$sponsor_tree[$uid][$level] = $upline_id;
					$downline_id = $upline_id;
				}else{
					unset ($downline_id);
				}
				$level += 1;
			}while ($downline_id && $level <= $matching_max_level);
			
			//foreach paired_comm as uid => position_pair
			for($j=0,$t2=count($paired_comm[$uid]);$j<$t2;$j++){
				//unset pairing_id
				//pairing_comm_amount = paired_comm[uid][index][paired_amount]
				//pairing_comm_unit = paired_comm[uid][index][paired_unit]
				unset ($pairing_id);
				$pairing_comm_amount = $paired_comm[$uid][$j]['paired_amount'];
				$pairing_comm_unit = $paired_comm[$uid][$j]['paired_unit'];
				$volume_type = $paired_comm[$uid][$j]['volume_type'];
				//insert the commission into the member_comm table with type = pairing, uid = uid, volume_type = volume_type, amount = pairing_comm_amount, leg1 = paired_comm[uid][index][leg1], leg1_id = paired_comm[uid][index][leg1_id], leg1_amount = paired_comm[uid][index][leg1_amount], leg2 = paired_comm[uid][index][leg2], leg2_id = paired_comm[uid][index][leg2_id], leg2_amount = paired_comm[uid][index][leg2_amount], paired_unit = paired_unit, year, month, day, datetime
				$sql="insert into $db->member_comm (uid, type, volume_type, amount, leg1, leg1_id, leg1_amount, leg2, leg2_id, leg2_amount, paired_unit, year, month, day, status, cdate) values ('$uid', 'p', '$volume_type', '$pairing_comm_amount', '{$paired_comm[$uid][$j]['leg1']}', '{$paired_comm[$uid][$j]['leg1_id']}', '{$paired_comm[$uid][$j]['leg1_amount']}', '{$paired_comm[$uid][$j]['leg2']}', '{$paired_comm[$uid][$j]['leg2_id']}', '{$paired_comm[$uid][$j]['leg2_amount']}', '$pairing_comm_unit', '$in_year', '$in_month', '$in_day', 'confirmed', '".ndate('Y-m-d H:i:s')."')";
				//if insert fail
					//record the error in the variable insert_pair_error
				$insert_comm_detail="UID: $uid Amount: $pairing_comm_amount Leg 1: {$paired_comm[$uid][$j]['leg1_id']}, Leg 2: {$paired_comm[$uid][$j]['leg2_id']} No. of Pair: $pairing_comm_unit Pairing Volume: $volume_type<br />\n";
				if(!mysql_query($sql)){
					$insert_pair_error.=$insert_comm_detail."SQL: $sql<br />\n";
				}else{
					$insert_pair_success.=$insert_comm_detail;
					//pairing_id = last insert id
					$pairing_id = mysql_insert_id();
				}
				
				//if isset sponsor_tree[uid]
				if (isset($sponsor_tree[$uid])){
					//foreach sponsor_tree[uid] as level => upline_id
					foreach ($sponsor_tree[$uid] as $level => $upline_id){
						//if not isset upline_info[upline_id]
						if (!isset($upline_info[$upline_id])){
							//upline_info[upline_id][sponsor] = get total downline sponsored by this upline_id before the end of month of input in_date
							//upline_info[upline_id][activated] = whether this upline_id is activated
							$upline_info[$upline_id]['sponsor'] = @mysql_result(mysql_query("select count(*) from $db->users where ref='$upline_id' and cdate<='$calc_date[end]'"), 0) or 0;
							$upline_info[$upline_id]['activated'] = $member_info[$upline_id]['activated'];
						}
						//upline_detail = upline_info[upline_id]
						$upline_detail = $upline_info[$upline_id];
						//if upline_detail[sponsor] >= matching_bonus[level][sponsor] and upline_detail[activated]
						if ($upline_detail['sponsor'] >= $matching_bonus[$level]['sponsor'] && $upline_detail['activated'] == 'y'){
							//matching_comm_amount = round(pairing_comm_amount * matching_bonus[level][percent] / 100, 2)
							$matching_comm_percent = $matching_bonus[$level]['percent'];
							$matching_comm_amount = round($pairing_comm_amount * $matching_comm_percent / 100, 2);
							//if pairing_id
							if ($pairing_id){
								//insert the commission into the member_comm table with type = matching, pid = pairing_id, uid = upline_id, from_uid = uid, amount = matching_comm_amount, level = level, percent = matching_bonus[level], year, month, datetime
								$sql="insert into $db->member_comm (uid, from_uid, type, pid, amount, level, percent, year, month, day, status, cdate) values ('$upline_id', '$uid', 'm', '$pairing_id', '$matching_comm_amount', '$level', '$matching_comm_percent', '$in_year', '$in_month', '$in_day', 'confirmed', '".ndate('Y-m-d H:i:s')."')";
								//if insert fail
									//record the error in the variable insert_matching_error
								$insert_comm_detail="UID: $uid Pairing ID: $pairing_id Amount: $matching_comm_amount Level: $level Percent: $matching_comm_percent%<br />\n";
								if(!mysql_query($sql)){
									$insert_matching_error.=$insert_comm_detail."SQL: $sql<br />\n";
								}else{
									$insert_matching_success.=$insert_comm_detail;
								}
							}else{
								//record the error in the variable insert_matching_error - pairing not properly inserted
								$insert_matching_error.="UID: $uid Pairing ID: Error! Amount: $matching_comm_amount Level: $level Percent: $matching_comm_percent%<br />\n";
							}
						}
					}
				}
			}
		}
	}
	
	if($insert_cf_error || $insert_pair_error || $insert_matching_error){
		$insert_errmsg.=($insert_cf_error? "Failed Recording Carry Forward:<br />\n<br />\n$insert_cf_error" : "").
		($insert_pair_error? "Failed Pairing Commission Calculation:<br />\n<br />\n$insert_pair_error" : "").
		($insert_matching_error? "Failed Matching Commission Calculation:<br />\n<br />\n$insert_matching_error" : "");
		$result["errmsg"] .= $insert_errmsg;
	}else{
		$result["status"] = true;
	}
	
	return $result;
}
?>